#include <Wire.h>
#include "RTClib.h"
#include <Bounce.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <LiquidCrystal.h>


//Real time cloc initialisation
RTC_DS1307 RTC;
//LCD initialisation
//arduino2560
LiquidCrystal lcd(47, 45, 41, 39, 37, 35);
//arduinonano
//LiquidCrystal lcd(4, 5, 6, 7, 8, 9);

// Temperatur wire is plugged into port 42 on the Arduino 2560
#define ONE_WIRE_BUS 42
// Temperatur wire is plugged into port 42 on the Arduino NANO
//#define ONE_WIRE_BUS 10

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);

// arrays to hold device address
DeviceAddress insideThermometer;

//Reley pins
#define RELAY1  6                   
#define RELAY2  7     

// the number of the pushbutton pin
const int buttonPin1 = 30;     
const int buttonPin2 = 32;
const int buttonPin3 = 34;     
const int buttonPin4 = 36;

// Instantiate a Bounce object with a 5 millisecond debounce time
Bounce bouncer1 = Bounce( buttonPin1,5 ); 
Bounce bouncer2 = Bounce( buttonPin2,2 ); 
Bounce bouncer3 = Bounce( buttonPin3,5 ); 
Bounce bouncer4 = Bounce( buttonPin4,5 ); 


//Arduino initial relay operation
int RELAY1_val = LOW;
int RELAY2_val = LOW;

//RELAY1 timer triger
boolean RELAY1_tr = false;
//RELAY1 Activation delay
int RELAY1_delay = 5;
//RELAY1 current time
long RELAY1_current_time;


// LED global brightness value in order to change color spectra

//warm white
const float led1glb = 1;
//Royal blue
const float led2glb = 1;
//Cold white
const float led3glb = 1;



//LED pins

int led1 =8;
int led2 =9;
int led3 =10;

// Full power brightness
const float ledFull = 0.8;
//Time needed to rise or shine in minutes
int sun_change_time = 20;
// LED brightness timestep in seconds considering ~20 minutes as sunset/sunshine period
int led_timer = int(sun_change_time * 60 / int(255 * ledFull ));

//LED timer triger
boolean led_tm_tr = true;

//LED fading max step
int led_step_mx = int(255 * ledFull);
//LED fading min step
int led_step_mn = 0;

//Есть смысл предусмотреть перезабуск в середине дня или ночи 
//и проверять sunshine относительно PM AM
// В случае середины дня запускать рассвет а в случае ночи ставить LED на ноль

boolean sunshine = true;

//LED current time
long current_time;


//Buzzer pin number
int pinSpeaker= 11;




volatile int NbTopsFan; //measuring the rising edges of the signal
int Calc;                               
int hallsensor = 2;    //The pin location of the sensor
 
void rpm ()     //This is the function that the interupt calls 
{ 
  NbTopsFan++;  //This function measures the rising and falling edge of the hall effect sensors signal
} 


//------------------------------------------------------------
//Time dependant lighting
//------------------------------------------------------------

//This two trigers are created in order to check for first set of morning evening times
boolean morning_state = false;
boolean evening_state = false;


//Light is off from "First Sunshine time" until "Second Sunshine time"

//First Sunrise time
int Sunrise_hour = 8;
int Sunrise_minutes = 1;

//First Sunshine time
int Sunshine_hour = 11;
int Sunshine_minutes = 1;

//Second Sunrise time for second cycle
int Sunrise_hour_2 = 19;
int Sunrise_minutes_2 = 1;

//Second Sunshine time for second cycle
int Sunshine_hour_2 = 22;
int Sunshine_minutes_2 = 1;

//------------------------------------------------------------
//Button dependant lighting
//------------------------------------------------------------
//This two trigers are created in order to check for first set of morning evening times
boolean morning_state_btn = false;
boolean evening_state_btn = false;



long oldTime = 0;
 
//Инициализации константы для температуры
float temp=0;

//___________________________________________________________________________________________


void setup() {
  
  //Датчик температуры, запуск
  sensors.begin();
  
  //Инициализировать порты кнопок как входы
  pinMode(buttonPin1, INPUT);    
  pinMode(buttonPin2, INPUT); 

  //Инициализировать порты подключения LED как выходы
    pinMode(led1, OUTPUT); 
    pinMode(led2, OUTPUT);
    pinMode(led3, OUTPUT);
     
  //Инициализировать порты подключения реле как выходы
  pinMode(RELAY1, OUTPUT);  
  pinMode(RELAY2, OUTPUT);  
  
   //Задать начальное положение реле (выключено)
  digitalWrite(RELAY1,RELAY1_val);           
  digitalWrite(RELAY2,RELAY2_val);           

  
//Инициализировать порт подключения динамика как выход
pinMode(pinSpeaker, OUTPUT);

//Инициализировать порт подключения расходомера как вход
pinMode(hallsensor, INPUT); 
attachInterrupt(0, rpm, RISING); //and the interrupt is attached
   
   

Serial.begin(19200);
    Wire.begin();
    //Start Clock
    RTC.begin();

DateTime now = RTC.now();
   // Выводим время в монитор порта
    Serial.print(now.year(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(' ');
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.println();
     sensors.requestTemperatures();
lcd.begin(20, 4);
lcd.clear();
  
}

//___________________________________________________________________________________________
//____________________________**************************************_________________________
//____________________________@    Конец инициализационного цикла  *_________________________
//____________________________**************************************_________________________
//___________________________________________________________________________________________

void loop() {

  
  sensors.setWaitForConversion(false);  // makes it async
  sensors.requestTemperatures();
  sensors.setWaitForConversion(true);
  
  

temp=sensors.getTempCByIndex(0);

    
  
  
   sei();      //Enables interrupts

//if (Calc < 690){tone(100, 8000);}

//This procces is a little slow......
// sensors.requestTemperatures(); // Send the command to get temperatures
//  temp=sensors.getTempCByIndex(0);
//   if (sensors.isConversionAvailable(0))
//  {
//    temp=sensors.getTempCByIndex(0);
//    sensors.requestTemperatures(); // prime the pump for the next one - but don't wait
//  }
  
  
//temp=sensors.getTempCByIndex(0);
 

if (temp > 26)
{
  tone(100, 5000);
}


//get time
   DateTime now = RTC.now();
   

   
   

   
//   Serial.println(led_step_mx); 
   

//Проверка условия по времени, если текущее время в часах и менутах равно заданному то активируется  тригер рассвет   
if (now.hour() == Sunrise_hour && now.minute() == Sunrise_minutes || now.hour() == Sunrise_hour_2 && now.minute() == Sunrise_minutes_2){morning_state = true ;}

//Проверка условия по времени, если текущее время в часах и менутах равно заданному то активируется  тригер закат   
if (now.hour() == Sunshine_hour && now.minute() == Sunshine_minutes || now.hour() == Sunshine_hour_2 && now.minute() == Sunshine_minutes_2){evening_state = true ;}  


   
   //Проверка условия по времени, если текущее время в часах и менутах больше заданного то начинается рассвет
   if (morning_state == true) 
         {
           
           lcd.setCursor(0,2); // Position cursor on line x=3,y=1
           lcd.print("Sunrise: ");
           lcd.print(led_step_mn);

              //Проверка условия по тригеру времени, который отвечает за ступенчатое повышение (понижение) яркости каждые X секунда (где X - задается переменной "led_timer" )   
              if (led_tm_tr == true ) 
                      {
                        //Определение следующего временного шага
                        current_time = now.unixtime() + led_timer;
                        led_tm_tr = false;
                        analogWrite(led1, int(led_step_mn));
                        analogWrite(led2, int(led_step_mn));
                        analogWrite(led3, int(led_step_mn));
                        Serial.println(now.unixtime());            
                        Serial.println(int(led_step_mn*led1glb)); 
                        led_step_mn++; 
                 
                            if (led_step_mn == led_step_mx + 1) //Сброс счетчика шагов яркости и тригира рассвета в момент достижения счетчиком заданного максимума
                              {
                                led_step_mn = 0;  
                                morning_state = false;
                                led_tm_tr = true;
                                Serial.print("Успешный сброс:"); 
                                Serial.println(sunshine); 
                                lcd.setCursor(0,2); // Position cursor on line x=3,y=1
                                lcd.print("                    ");
                                
                              }
                             
                      }
                   //сравнение текущего времени с ранее определенным временным шагом и переведение тригера "led_tm_tr" в true в случае соблюдения условия        
                   if ( now.unixtime() >= current_time) 
                      {
                        led_tm_tr = true;
                      }
         }
   
   
    
   
   
   
   //Проверка условия по времени, если текущее время в часах и менутах больше заданного то начинается закат
   if (evening_state == true) 
         {
           lcd.setCursor(0,2); // Position cursor on line x=3,y=1
           lcd.print("Sunset: ");
           lcd.print(led_step_mn);

              //Проверка условия по тригеру времени, который отвечает за ступенчатое повышение (понижение) яркости каждые X секунда (где X - задается переменной "led_timer" )   
              if (led_tm_tr == true ) 
                      {
                        //Определение следующего временного шага
                        current_time = now.unixtime() + led_timer;
                        led_tm_tr = false;
                        analogWrite(led1, int(led_step_mx*led1glb));
                        analogWrite(led2, int(led_step_mx*led2glb));
                        analogWrite(led3, int(led_step_mx*led3glb));
                        Serial.println(now.unixtime());            
                        Serial.println(led_step_mx); 
                        led_step_mx--;
                            if (led_step_mx == led_step_mn - 1) //Сброс счетчика шагов яркости и тригира рассвета в момент достижения счетчиком заданного максимума
                              {
                                led_step_mx=int(255 * ledFull);  
                                evening_state = false;
                                Serial.print("Успешный сброс:"); 
                                Serial.println(sunshine); 
                                lcd.setCursor(0,2); // Position cursor on line x=3,y=1
                                lcd.print("                    ");

                                                                
                              }
                      
                      }
                   //сравнение текущего времени с ранее определенным временным шагом и переведение тригера "led_tm_tr" в true в случае соблюдения условия        
                   if ( now.unixtime() >= current_time) 
                      {
                        led_tm_tr = true;
                      }
         }
   
   
    
   
   
   
   
   //Screem reinitialisation in order to avoid weird characters
   
   if (now.unixtime() > oldTime + 30) {
     LiquidCrystal lcd(47, 45, 41, 39, 37, 35);
     lcd.begin(20, 4);
     lcd.clear();
     oldTime = now.unixtime();
         }
        
        
        
        
        
     //   if (Calc < 690){tone(100, 8000);}


  
 

if (temp > 27)
{
  tone(100, 5000);
}
        
        
        
        
        
        
        
        
   
    
 Serial.print("Water T: ");
Serial.println(temp); 
  Serial.print (Calc, DEC); //Prints the number calculated above
  Serial.print (" L/hour\r\n"); //Prints "L/hour" and returns a  new line
  
  
  //Sunrise time for second cycle

//  Serial.println (Sunrise_hour);
//  Serial.println (Sunrise_minutes);
//  Serial.println (Sunshine_hour);
//  Serial.println (Sunshine_minutes);


//  Serial.println (Sunrise_hour_2);
//  Serial.println (Sunrise_minutes_2);
//  Serial.println (Sunshine_hour_2);
//  Serial.println (Sunshine_minutes_2);

  
    char buf[50]; 
    sprintf(buf, "%02d/%02d/%4d %02d:%02d:%02d", now.day(), now.month(), now.year(), now.hour(), now.minute(), now.second()); 
    Serial.println(buf); 
    lcd.setCursor(0,0); //Start at character 0 on line 0
    lcd.print(buf);
    lcd.setCursor(0,1); // Position cursor on line x=3,y=1
 lcd.print("Water T: ");    
lcd.print(temp);   


 


    




//Включение и выключение реле по одиночному нажатию, с учетом дебоунси
  
  if ( bouncer2.update() ) {
    
      if ( bouncer2.read() == HIGH) {
       if ( RELAY2_val == LOW ) {
         RELAY2_val = HIGH;
       } else {
         RELAY2_val = LOW;
       }
       digitalWrite(RELAY2,RELAY2_val);
     }
   }
  
  
  //Включение и выключение реле по одиночному нажатию, с учетом дебоунси
  
  if ( bouncer3.update() ) {
    
      if ( bouncer3.read() == HIGH) {
       if ( RELAY2_val == LOW ) {
         RELAY2_val = HIGH;
       } else {
         RELAY2_val = LOW;
       }
       digitalWrite(RELAY2,RELAY2_val);
     }
   }
  
  
  //Включение и выключение реле по одиночному нажатию, с учетом дебоунси
  
  if ( bouncer4.update() ) {
    
      if ( bouncer4.read() == HIGH) {
       if ( RELAY2_val == LOW ) {
         RELAY2_val = HIGH;
       } else {
         RELAY2_val = LOW;
       }
       digitalWrite(RELAY2,RELAY2_val);
     }
   }
  
  
  
    
//Включение и выключение реле с учетом того, что кнопка должна быть нажата "RELAY1_delay" секунд с учетом дебоунси
   if ( bouncer1.update() && bouncer1.read() == HIGH) 
    {
    RELAY1_current_time = now.unixtime() + RELAY1_delay;
    RELAY1_tr = !RELAY1_tr;
    }
 
 
 if ( now.unixtime() >= RELAY1_current_time && RELAY1_tr == true) 
      {

 //      if ( RELAY1_val == LOW ) {
 //        RELAY1_val = HIGH;
 //      } else {
 //       RELAY1_val = LOW;
 //      }
 //      digitalWrite(RELAY1,RELAY1_val);
       morning_state = true ;
       tone(100, 5000); 
       RELAY1_tr = false;
     }
                      
 
 
 

//Flowaret measurment

  NbTopsFan = 0;   //Set NbTops to 0 ready for calculations
  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  //Данная задержка влияет на работу кнопок
//  delay (1000);   //Wait 1 second
  cli();      //Disable interrupts
  Calc = (NbTopsFan * 60 / 4.8); //(Pulse frequency x 60) / 5.5Q, = flow rate in L/hour 
  
  
  

   
 





}


//___________________________________________________________________________________________


 //Buzzer signals  routine
void tone(long duration, int freq) {
duration *= 1000;
int period = (1.0 / freq) * 1000000;
long elapsed_time = 0;
while (elapsed_time < duration) {
digitalWrite(pinSpeaker,HIGH);
delayMicroseconds(period / 2);
digitalWrite(pinSpeaker, LOW);
delayMicroseconds(period / 2);
elapsed_time += (period);
}
  }

